/** * Template - A Component which replicates itself and its children for each object in its model. * * Copyright (c) 2002 * Marty Phelan, All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package com.taursys.xml; import com.taursys.xml.event.*; import com.taursys.xml.render.TemplateRenderer; import com.taursys.xml.render.DocumentElementRenderer; import com.taursys.model.CollectionValueHolder; /** * <p>A <code>Template</code> is a component used to display and/or input multiple * values. It acts as a <code>Container</code> for other components which * provide the actual display or input. A typical application for the * <code>Template</code> is to display or edit a table of data. The * <code>Template</code> is bound to a single tag in the XML document. This * tag in turn contains other tags that make up the "template" row. The * <code>Template</code> is also bound to a CollectionValueHolder which * contains the values. When rendered, the Template will replicate itself * (and its child tags) in the XML document for each value in the holder. * </p> * <p>The following is an example illustrates a <code>Template</code> used to * display a list of names (from a collection of Person objects). A portion * of the HTML is listed below along with a portion of the java code. The * initForm and openForm methods have been ommitted. The * <code>HTMLComponentFactory</code> was not used in this example so that * the actual components could be illustrated. * </p> * <pre> * <h2>List presented in a table</h2> * <table border="1"> * <tr> * <td >First Name</td> * <td >Last Name</td> * </tr> * <tr id="People__TEMPLATE_NODE"> * <td id="People__firstName">John</td> * <td id="People__lastName">Smith</td> * </tr> * </table> * * ----------------------------------------------------------------------- * * public class TemplatePage extends ServletForm { * VOCollectionValueHolder people = new VOCollectionValueHolder(); * // =================================================================== * // The following code can be ommitted if the component factory is used * // =================================================================== * TextField firstName = new TextField(); * TextField lastName = new TextField(); * Template report = new Template(); * // =================================================================== * * public TemplatePage() { * try { * jbInit(); * } catch(Exception e) { * e.printStackTrace(); * } * } * * private void jbInit() throws Exception { * people.setAlias("People"); * people.setValueObjectClass(Person.class); * // =================================================================== * // The following code can be ommitted if the component factory is used * // =================================================================== * firstName.setPropertyName(Person.FIRST_NAME); * firstName.setValueHolder(people); * firstName.setId("People__firstName"); * lastName.setPropertyName(Person.LAST_NAME); * lastName.setValueHolder(people); * lastName.setId("People__lastName"); * report.setId("report"); * report.setCollectionValueHolder(people); * report.add(firstName); * report.add(lastName); * this.add(report); * // =================================================================== * } * </pre> * * <p>A <code>Template</code> can also be used to input multiple values. The code * is essentially the same, except that you will use input type components * in the HTML and Java code. The order and count of the values in the request * must correspond to the order and count in the holder. The BusinessDelegate * that supplies the values should ensure this. * </p> * <p>The following example illustrates a form to edit inventory items. A portion * of the HTML is listed below along with a portion of the java code. The * openForm methods has been ommitted. This example uses the HTMLComponent * factory to create the actual components at runtime. * </p> * <pre> * * <h2>List of Inventory Items to Edit</h2> * <form method="post" action="InventoryEditPage.sf"> * <table border="1" width="100%"> * <tr bgcolor="orange"> * <td>Quantity</td> * <td>Product ID</td> * <td>Unit Price</td> * <td>Extension</td> * </tr> * <tr id="Inventory__TEMPLATE_NODE"> * <td> * <input type="text" id="Inventory__quantity" name="quantity" value="1"/> * </td> * <td id="Inventory__productID">XXXX</td> * <td> * <input type="text" id="Inventory__unitPrice" name="unitPrice" value="0.00"/> * </td> * <td id="Inventory__extension">0.00</td> * </tr> * </table> * <br/> * <input type="submit" name="action" value="Save"/> * </form> * * ----------------------------------------------------------------------- * * public class InventoryEditPage extends ServletForm { * private VOListValueHolder inventoryHolder = new VOListValueHolder(); * * public InventoryEditPage() { * try { * jbInit(); * } catch(Exception e) { * e.printStackTrace(); * } * } * * private void jbInit() throws Exception { * inventoryHolder.setAlias("Inventory"); * inventoryHolder.setValueObjectClass(InvoiceItemVO.class); * this.add(warehouseField); * } * * protected void initForm() throws java.lang.Exception { * super.initForm(); * DOMParser parser = new DOMParser(); * InputSource is = new InputSource( * getClass().getResourceAsStream("InventoryEditPage.html")); * parser.parse(is); * this.setDocument(parser.getDocument()); * // Use HTMLComponentFactory to create components * HTMLComponentFactory.getInstance().createComponents(this, * new ValueHolder[] {inventoryHolder}); * } * </pre> * <p>Technical Information: * </p> * <p>The <code>Template</code> uses a <code>TemplateRenderer</code> to do the * actual rendering. Typically, this involves dispatching a * <code>RenderEvent</code> to its children, then cloning itself for each item * in its <code>collectionValueHolder</code>. * </p> * <p>The <code>Template</code> creates specialized dispatchers for Input and * Trigger events. These dispatchers iterate over each item in the collection * (in the order of the iterator), increment the parameter index and dispatch * input to child components. * </p> */ public class Template extends DocumentElement { private CollectionValueHolder collectionValueHolder; /** * Constructs a new template */ public Template() { } // ======================================================================= // Create Dispatchers // ======================================================================= /** * Create the InputDispatcher for this Container. * @return the InputDispatcher for this Container. */ protected InputDispatcher createInputDispatcher() { return new TemplateInputDispatcher(this); } /** * Create the TriggerDispatcher for this Container. * @return the TriggerDispatcher for this Container. */ protected TriggerDispatcher createTriggerDispatcher() { return new TemplateTriggerDispatcher(this); } // ======================================================================= // Create Renderer // ======================================================================= /** * Creates the default Renderer for this component. * By Default this methos returns a new TemplateRenderer. * Override this method to define your own TemplateRenderer. */ protected DocumentElementRenderer createDefaultRenderer() { return new TemplateRenderer(this); } /** * Set the CollectionValueHolder that this template will iterate for rendering. * @param holder the CollectionValueHolder that this template will iterate for * rendering. */ public void setCollectionValueHolder(CollectionValueHolder holder) { collectionValueHolder = holder; } // ======================================================================= // Property Accessors // ======================================================================= /** * Get the CollectionValueHolder that this template will iterate for rendering. * @return the CollectionValueHolder that this template will iterate for * rendering. */ public CollectionValueHolder getCollectionValueHolder() { return collectionValueHolder; } }